package com.smsc.headend.task.engine.executor.impl.ansi;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.HexUtil;
import com.smsc.headend.common.enums.errorcode.TaskExecuteErrorCode;
import com.smsc.headend.common.utils.RedisUtils;
import com.smsc.headend.module.asset.dmo.ComConfigDMO;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.common.entity.DeviceOperation;
import com.smsc.headend.module.data.dmo.DeviceSAPandKeys;
import com.smsc.headend.module.data.dto.DataItemDTO;
import com.smsc.headend.module.data.enums.DictionaryType;
import com.smsc.headend.module.data.enums.OperationName;
import com.smsc.headend.module.protocol.ansi.AnsiByteBuffer;
import com.smsc.headend.module.protocol.cosem.util.ByteUtils;
import com.smsc.headend.module.report.entity.LogScheduleTaskDevice;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.AtomicTaskState;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.task.enums.TaskType;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskExecutorException;
import com.smsc.headend.task.engine.executor.TaskExecutor;
import com.smsc.headend.task.engine.facade.DataItemFacade;
import com.smsc.headend.task.engine.handler.impl.ansi.GetLpSettingHandler;
import com.smsc.headend.task.engine.handler.impl.ansi.GetLpStatusHandler;
import com.smsc.headend.task.engine.service.ConnectorService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import com.smsc.headend.task.engine.service.task.LogScheduleTaskDeviceService;
import com.smsc.headend.task.engine.service.task.TaskPacketService;
import com.smsc.headend.task.engine.utils.AnsiUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;

@Slf4j
public class GetLpConfigExecutor implements TaskExecutor {
    @Autowired
    TaskPacketService packetService;
    @Autowired
    ConnectorService connectorService;

    @Autowired
    RedisUtils redisUtils;
    @Autowired
    FeignAssetManagementService assetManagementRemoteService;
    @Autowired
    DataItemFacade dataItemFacade;

    @Autowired
    KafkaTemplate kafkaTemplate;
    @Autowired
    TaskDAO taskDAO;
    @Autowired
    AssetService assetService;
    @Autowired
    LogScheduleTaskDeviceService logScheduleTaskDeviceService;

    @Override
    public AtomicTaskState execute(Task task, AtomicTask atomicTask) throws UDISTaskExecutorException {
        task.setFailStop(true);
        taskDAO.updateTask(task);
        Meter meter = getMeter(task, assetService);
        DeviceOperation dictionary = assetService.getDictionary(atomicTask.getOperationId(), DictionaryType.Operation.getType());
        ComConfigDMO comConfigDMO = assetService.getComConfigById(task.getComId());
        List<DataItemDTO> dataItemCosemList = dataItemFacade.getDataItemsByOperation(meter, null, dictionary, getParameterMap(task, atomicTask), comConfigDMO == null ? null : comConfigDMO.getModelId());
        if (CollectionUtils.isEmpty(dataItemCosemList)) {
            throw new UDISTaskExecutorException(TaskExecuteErrorCode.DATAITEM_NOT_EXISTS.toString());
        }
        DataItemDTO dataItemDTO = dataItemCosemList.get(0);
        DeviceSAPandKeys deviceKeys = assetManagementRemoteService.getMeterCommunicationKey(meter.getMeterId(), dataItemDTO.getRoleId());
        byte[] packets = packetService.buildReadOneAttributePacket(dataItemCosemList.get(0), comConfigDMO, deviceKeys);
        log.debug(ByteUtils.byteToHexString(packets));
        connectorService.sendPacket(task, atomicTask, dataItemCosemList.get(0).getRoleId(), task.getIsODR(), packets);
        return createAtomicState(loadProfileReadHandler(atomicTask));
    }

    private Class loadProfileReadHandler(AtomicTask atomicTask) {
        OperationName operationName = OperationName.forId(atomicTask.getOperationId());
        switch (operationName) {
            case GetLpSetting:
                return GetLpSettingHandler.class;
            case GetLpStatus:
                return GetLpStatusHandler.class;
            default:
                return null;
        }
    }

    @Override
    public Boolean handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.info("error {}, ", message);
        if (task.getIsODR()) {
            Map<String, Object> param = getParameterMap(task, atomicTask);
            Long profileDataItemId = Long.valueOf(String.valueOf(param.get("dataItemId")));
            // key 回曲线的dataItemId给web
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(profileDataItemId), message, 3600l, false);
        }
        if ((TaskType.ScheduleRead_Profile.toString().equalsIgnoreCase(task.getTaskType()) && !message.equals(TaskExecuteErrorCode.SCHEDULE_TASK_IS_LATEST_PROCESS.toString()))
                || TaskType.EventRead_Profile.toString().equalsIgnoreCase(task.getTaskType())
                || TaskType.ScheduleRead_LogBook.toString().equalsIgnoreCase(task.getTaskType())) {
            logScheduleTaskDeviceService.sendMessage(task, LogScheduleTaskDevice.StatusEnum.Failed.getCode(), LogScheduleTaskDevice.StatusDescEnum.DecodeDataFailed.getCode());
        }
        return true;
    }
}
